package com.zgx.plus.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.zgx.plus.common.aop.DataScope;
import com.zgx.plus.common.constant.ComConstant;
import com.zgx.plus.common.exception.BizException;
import com.zgx.plus.common.utils.SecurityUtils;
import com.zgx.plus.system.api.dto.SysDeptDto;
import com.zgx.plus.system.api.pos.SysDept;
import com.zgx.plus.system.api.pos.SysRole;
import com.zgx.plus.system.api.pos.SysRoleDept;
import com.zgx.plus.system.api.pos.SysUser;
import com.zgx.plus.system.api.vos.SysDeptVo;
import com.zgx.plus.system.api.vos.TreeSelect;
import com.zgx.plus.system.mapper.SysDeptMapper;
import com.zgx.plus.system.mapper.SysRoleDeptMapper;
import com.zgx.plus.system.mapper.SysRoleMapper;
import com.zgx.plus.system.mapper.SysUserMapper;
import com.zgx.plus.system.service.SysDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleDeptMapper sysRoleDeptMapper;

    /**
     *      * 查询部门管理数据
     *      *
     *      * @param dept 部门信息
     *      * @return 部门信息集合
     *      
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysDeptVo> selectDeptList(SysDeptDto dept) {
        Long deptId = dept.getDeptId();
        Long parentId = dept.getParentId();
        Object obj = dept.getParams().get(ComConstant.KEY_DATA_SCOPE);
        String dataScopeSql = Objects.isNull(obj) ? null : (StrUtil.removePrefix(String.valueOf(obj).trim(), "AND"));

        return Convert.toList(SysDeptVo.class, this.list(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getDelFlag, 0)
                .eq((Objects.nonNull(deptId) && !Objects.equals(deptId, 0L)), SysDept::getDeptId, deptId)
                .eq((Objects.nonNull(parentId) && !Objects.equals(parentId, 0L)), SysDept::getParentId, parentId)
                .eq(StrUtil.isNotBlank(dept.getStatus()), SysDept::getStatus, dept.getStatus())
                .like(StrUtil.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName())
                .apply(StrUtil.isNotBlank(dataScopeSql), dataScopeSql)
                .orderByAsc(Arrays.asList(SysDept::getParentId, SysDept::getOrderNum))));
    }

    /**
     *      * 根据部门ID查询信息
     *      *
     *      * @param deptId 部门ID
     *      * @return 部门信息
     *      
     */
    @Override
    public SysDeptVo selectDeptById(Long deptId) {
        if (!SecurityUtils.isCurrentUserAdmin()) {
            if (!SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getDelFlag, 0).eq(SysDept::getDeptId, deptId)))) {
                throw new BizException("没有权限访问部门数据！");
            }
        }
        SysDeptVo sysDeptVo = Convert.convert(SysDeptVo.class, this.getById(deptId));
        sysDeptVo.setParentName(this.getObj(Wrappers.lambdaQuery(SysDept.class)
                        .select(SysDept::getDeptName).eq(SysDept::getDeptId, sysDeptVo.getParentId()),
                parentName -> Objects.isNull(parentName) ? null : String.valueOf(parentName)));
        return sysDeptVo;
    }


    /**
     *      * 新增保存部门信息
     *      * ①、父部门是否停用
     *      * ②、该父部门下是否存在相同的部门
     *      *
     *      * @param dept 部门信息
     *      * @return 结果
     *      
     */
    @Override
    public boolean insertDept(SysDeptVo dept) {
        String parentStatus = this.getObj(Wrappers.lambdaQuery(SysDept.class).select(SysDept::getStatus).eq(SysDept::getDeptId, dept.getParentId()),
                parentStatusObj -> Objects.isNull(parentStatusObj) ? null : String.valueOf(parentStatusObj));
        Assert.isTrue(StrUtil.equals(ComConstant.STATUS_NORMAL, parentStatus), () -> new BizException(MessageFormat.format("新增部门{0}失败，父部门不可用", dept.getDeptName())));

        SysDept currUser = this.getOne(Wrappers.lambdaQuery(SysDept.class)
                .eq(SysDept::getDeptName, dept.getDeptName()).eq(SysDept::getParentId, dept.getParentId()));

        if (Objects.isNull(currUser)) {
            String ancestors = this.getObj(Wrappers.lambdaQuery(SysDept.class).select(SysDept::getAncestors).eq(SysDept::getDeptId, dept.getParentId()),
                    parentAncestors -> Objects.isNull(parentAncestors) ? String.valueOf(dept.getParentId()) : (parentAncestors + "," + dept.getParentId()));
            dept.setAncestors(ancestors);
            return this.save(dept);
        }
        if (StrUtil.equals(currUser.getStatus(), ComConstant.STATUS_NORMAL) && StrUtil.equals(currUser.getDelFlag(), ComConstant.FLAG_EXIST)) {
            throw new BizException(MessageFormat.format("新增部门{0}已存在", dept.getDeptName()));
        }
        currUser.setStatus(ComConstant.STATUS_NORMAL);
        currUser.setDelFlag(ComConstant.FLAG_EXIST);
        this.updateById(currUser);
        return true;
    }


    /**
     *      * 修改保存部门信息
     *      *
     *      * @param dept 部门信息
     *      * @return 结果
     *      
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateDept(SysDeptVo dept) {
        SysDept parentSysDept = this.getOne(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getDeptId, dept.getParentId()));
        Assert.isFalse(Objects.isNull(parentSysDept), () -> new BizException("上级部门不存在"));

        dept.setAncestors(StrUtil.concat(true, parentSysDept.getAncestors(), ",", String.valueOf(parentSysDept.getDeptId())));
        this.updateById(dept);

        String childAncestors = StrUtil.concat(true, dept.getAncestors(), ",", String.valueOf(dept.getDeptId()));
        this.update(Wrappers.lambdaUpdate(SysDept.class).set(SysDept::getAncestors, childAncestors).apply("find_in_set({0}, ancestors)", dept.getDeptId()));
        return true;
    }

    /**
     *      * 删除部门管理信息
     *      * ①、该部门挂有子部门不允许删除
     *      * ②、该部门存在用户不允许删除
     *      *
     *      * @param deptId 部门ID
     *      * @return 结果
     *      
     */
    @Override
    public boolean deleteDeptById(Long deptId) {
        boolean retExist = SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysDept.class).apply("find_in_set({0},ancestors)", deptId)));
        Assert.isFalse(retExist, () -> new BizException("存在子部门"));
        boolean retExistUser = SqlHelper.retBool(sysUserMapper.selectCount(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getDeptId, deptId).eq(SysUser::getDelFlag, ComConstant.FLAG_EXIST)));
        Assert.isFalse(retExistUser, () -> new BizException("该部门存在用户"));
        return this.removeById(deptId);
    }


    /**
     *      * 查询部门树结构信息
     *      *
     *      * @param dept 部门信息
     *      * @return 部门树信息集合
     *      
     */
    @Override
    public List<TreeSelect> selectDeptTreeList(SysDeptDto dept) {
// List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
        return buildDeptTreeSelect(this.selectDeptList(dept));
    }


    /**
     *      * 构建前端所需要下拉树结构
     *      *
     *      * @param depts 部门列表
     *      * @return 下拉树结构列表
     *      
     */
    public List<TreeSelect> buildDeptTreeSelect(List<SysDeptVo> depts) {
        return buildDeptTree(depts).stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     *      * 构建前端所需要树结构
     *      *
     *      * @param depts 部门列表
     *      * @return 树结构列表
     *      
     */

    public List<SysDeptVo> buildDeptTree(List<SysDeptVo> depts) {
        List<SysDeptVo> returnList = new ArrayList<>();
        List<Long> tempList = depts.stream().map(SysDeptVo::getDeptId).collect(Collectors.toList());
        for (SysDeptVo dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }


    /**
     *      * 根据角色ID查询部门树信息
     *      *
     *      * @param roleId 角色ID
     *      * @return 选中部门列表
     *      
     */
    @Override
    public List<Long> selectDeptListByRoleId(Long roleId) {
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        log.info(JSON.toJSONString(sysRole));
        List<Long> deptIds = sysRoleDeptMapper.selectList(Wrappers.lambdaQuery(SysRoleDept.class).select(SysRoleDept::getDeptId).eq(SysRoleDept::getRoleId, roleId))
                .stream().filter(Objects::nonNull).map(SysRoleDept::getDeptId).collect(Collectors.toList());
        List<Long> realdeptIds = this.listObjs(Wrappers.lambdaQuery(SysDept.class).select(SysDept::getDeptId).in(SysDept::getDeptId, deptIds), deptId -> Long.parseLong(String.valueOf(deptId)));
        if (!sysRole.getDeptCheckStrictly()) {
            List<Long> parentIds = this.listObjs(Wrappers.lambdaQuery(SysDept.class).select(SysDept::getParentId).in(SysDept::getDeptId, deptIds), parentId -> Long.parseLong(String.valueOf(parentId)));
            return realdeptIds.stream().filter(id -> !CollUtil.contains(parentIds, id)).collect(Collectors.toList());
        }
        return realdeptIds;
    }

//
// /**
//     * 是否存在子节点
//     *
//     * @param deptId 部门ID
//     * @return 结果
//     */
// @Override
// public boolean hasChildByDeptId(Long deptId) {
//// int result = deptMapper.hasChildByDeptId(deptId);
//// return result > 0;
// return true;
// }
//
// /**
//     * 查询部门是否存在用户
//     *
//     * @param deptId 部门ID
//     * @return 结果 true 存在 false 不存在
//     */
// @Override
// public boolean checkDeptExistUser(Long deptId) {
//// int result = deptMapper.checkDeptExistUser(deptId);
//// return result > 0;
// return true;
// }
//
// /**
//     * 校验部门名称是否唯一
//     *
//     * @param dept 部门信息
//     * @return 结果
//     */
// @Override
// public boolean checkDeptNameUnique(SysDept dept) {
//// Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
//// SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
//// if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) {
//// return UserConstants.NOT_UNIQUE;
//// }
//// return UserConstants.UNIQUE;
// return true;
// }
//
// /**
//     * 校验部门是否有数据权限
//     *
//     * @param deptId 部门id
//     */
// @Override
// public void checkDeptDataScope(Long deptId) {
// if (!SecurityUtils.isCurrentUserAdmin()) {
//// SysDept dept = new SysDept();
//// dept.setDeptId(deptId);
//// List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
//// if (StringUtils.isEmpty(depts)) {
//// throw new BizException("没有权限访问部门数据！");
//// }
// if (SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getDelFlag, 0).eq(SysDept::getDeptId, deptId)))) {
// throw new BizException("没有权限访问部门数据！");
// }
// }
// }
//
//
// /**
//     * 修改该部门的父级部门状态
//     *
//     * @param dept 当前部门
//     */
// private void updateParentDeptStatusNormal(SysDept dept) {
// Long[] deptIds = Convert.toLongArray(dept.getAncestors());
// this.update(Wrappers.lambdaUpdate(SysDept.class).set(SysDept::getStatus, ComConstant.STATUS_NORMAL).in(SysDept::getDeptId, Arrays.asList(deptIds)));
// }
//
// /**
//     * 修改子元素关系
//     *
//     * @param deptId       被修改的部门ID
//     * @param newAncestors 新的父ID集合
//     * @param oldAncestors 旧的父ID集合
//     */
// public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
// List<SysDept> childrenList = deptMapper.selectChildrenDeptById(deptId);
// for (SysDept child : childrenList) {
// child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
// }
// if (childrenList.size() > 0) {
// this.saveOrUpdateBatch(childrenList);
// }
// }

    /**
     *      * 递归列表
     *      
     */
    private void recursionFn(List<SysDeptVo> list, SysDeptVo deptVo) {
        // 得到子节点列表
        List<SysDeptVo> childList = getChildList(list, deptVo);
        deptVo.setChildren(childList);
        for (SysDeptVo tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     *      * 得到子节点列表
     *      
     */
    private List<SysDeptVo> getChildList(List<SysDeptVo> list, SysDeptVo t) {
        return list.stream().filter(dept -> (Objects.nonNull(dept.getParentId()) && Objects.equals(dept.getParentId(), t.getDeptId()))).collect(Collectors.toList());
    }

    /**
     *      * 判断是否有子节点
     *      
     */
    private boolean hasChild(List<SysDeptVo> list, SysDeptVo t) {
        return getChildList(list, t).size() > 0;
    }

}
